package com.mall.module.system.service.Impl;

import com.github.pagehelper.PageHelper;
import com.mall.common.exception.BusinessException;
import com.mall.common.model.PageResult;
import com.mall.common.result.ResultCode;
import com.mall.common.util.UserContext;
import com.mall.module.system.domain.dto.CreateDeptDTO;
import com.mall.module.system.domain.dto.UpdateDeptDTO;
import com.mall.module.system.domain.entity.SysDept;
import com.mall.module.system.domain.vo.CreateDeptVO;
import com.mall.module.system.domain.vo.DeptDetailVO;
import com.mall.module.system.domain.vo.DeptTreeNodeVO;
import com.mall.module.system.mapper.SysDeptMapper;
import com.mall.module.system.service.SysDeptService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 部门服务实现类
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class SysDeptServiceImpl implements SysDeptService {

    private final SysDeptMapper deptMapper;

    @Override
    @Transactional
    public CreateDeptVO createDept(CreateDeptDTO dto) {
        // 1. 参数校验
        validateCreateDept(dto);

        // 2. 检查部门名称唯一性
        if (deptMapper.existsByName(dto.getName(), dto.getParentId(), null)) {
            throw new BusinessException(ResultCode.CONFLICT,"同级部门下已存在相同名称的部门");
        }

        // 3. 检查部门编码唯一性（如果提供了编码）
        if (StringUtils.hasText(dto.getDeptCode()) && deptMapper.existsByDeptCode(dto.getDeptCode(), null)) {
            throw new BusinessException(ResultCode.CONFLICT,"部门编码已存在");
        }

        // 4. 创建部门实体
        SysDept dept = new SysDept();
        BeanUtils.copyProperties(dto, dept);

        // 5. 设置系统字段
        dept.setStatus(1); // 默认启用
        dept.setCreateTime(LocalDateTime.now());
        dept.setUpdateTime(LocalDateTime.now());
        dept.setIsDeleted(0);
        dept.setCreatorId(UserContext.getUserId());
        dept.setUpdaterId(UserContext.getUserId());

        // 6. 处理空值字段
        if (dept.getOrderNum() == null) dept.setOrderNum(0);
        if (dept.getDeptType() == null) dept.setDeptType(2);

        // 7. 保存到数据库
        deptMapper.insert(dept);

        log.info("部门创建成功，部门ID: {}, 部门名称: {}", dept.getId(), dept.getName());

        // 8. 返回创建结果
        return CreateDeptVO.builder()
            .id(dept.getId())
            .name(dept.getName())
            .parentId(dept.getParentId())
            .orderNum(dept.getOrderNum())
            .deptCode(dept.getDeptCode())
            .deptType(dept.getDeptType())
            .leaderId(dept.getLeaderId())
            .phone(dept.getPhone())
            .email(dept.getEmail())
            .address(dept.getAddress())
            .description(dept.getDescription())
            .status(dept.getStatus())
            .createTime(dept.getCreateTime())
            .build();
    }

    @Override
    @Transactional
    public CreateDeptVO updateDept(UpdateDeptDTO dto) {
        // 1. 参数校验
        validateUpdateDept(dto);

        // 2. 检查部门是否存在
        SysDept existingDept = deptMapper.selectById(dto.getDeptId());
        if (existingDept == null) {
            throw new BusinessException(ResultCode.CONFLICT,"部门不存在");
        }

        // 3. 检查部门名称唯一性
        if (StringUtils.hasText(dto.getName()) && 
            deptMapper.existsByName(dto.getName(), dto.getParentId() != null ? dto.getParentId() : existingDept.getParentId(), dto.getDeptId())) {
            throw new BusinessException(ResultCode.CONFLICT,"同级部门下已存在相同名称的部门");
        }

        // 4. 检查部门编码唯一性
        if (StringUtils.hasText(dto.getDeptCode()) && deptMapper.existsByDeptCode(dto.getDeptCode(), dto.getDeptId())) {
            throw new BusinessException(ResultCode.CONFLICT,"部门编码已存在");
        }

        // 5. 更新部门信息
        SysDept dept = new SysDept();
        BeanUtils.copyProperties(dto, dept);
        dept.setUpdateTime(LocalDateTime.now());
        dept.setUpdaterId(UserContext.getUserId());

        deptMapper.updateById(dept);

        log.info("部门更新成功，部门ID: {}", dto.getDeptId());

        // 6. 返回更新结果
        return CreateDeptVO.builder()
            .id(dept.getId())
            .name(dept.getName())
            .parentId(dept.getParentId())
            .orderNum(dept.getOrderNum())
            .deptCode(dept.getDeptCode())
            .deptType(dept.getDeptType())
            .leaderId(dept.getLeaderId())
            .phone(dept.getPhone())
            .email(dept.getEmail())
            .address(dept.getAddress())
            .description(dept.getDescription())
            .status(dept.getStatus())
            .createTime(existingDept.getCreateTime())
            .build();
    }

    @Override
    @Transactional
    public void deleteDept(Long deptId) {
        // 1. 检查部门是否存在
        SysDept dept = deptMapper.selectById(deptId);
        if (dept == null) {
            throw new BusinessException(ResultCode.CONFLICT,"部门不存在");
        }

        // 2. 检查是否有子部门
        List<SysDept> children = deptMapper.selectByParentId(deptId);
        if (!children.isEmpty()) {
            throw new BusinessException(ResultCode.CONFLICT,"该部门下还有子部门，无法删除");
        }

        // 3. 检查是否有用户
        int userCount = deptMapper.countUsersByDeptId(deptId);
        if (userCount > 0) {
            throw new BusinessException(ResultCode.CONFLICT,"该部门下还有用户，无法删除");
        }

        // 4. 逻辑删除部门
        deptMapper.deleteById(deptId, UserContext.getUserId());

        log.info("部门删除成功，部门ID: {}", deptId);
    }

    @Override
    public DeptDetailVO getDeptDetail(Long deptId) {
        // 1. 查询部门信息（包含父部门）
        SysDept dept = deptMapper.selectByIdWithParent(deptId);
        if (dept == null) {
            throw new BusinessException(ResultCode.CONFLICT,"部门不存在");
        }

        // 2. 统计用户数量
        int userCount = deptMapper.countUsersByDeptId(deptId);

        // 3. 获取部门路径
        String deptPath = deptMapper.selectDeptPath(deptId);

        // 4. 构建返回结果
        return DeptDetailVO.builder()
            .id(dept.getId())
            .name(dept.getName())
            .parentId(dept.getParentId())
            .parentName(dept.getParentName())
            .orderNum(dept.getOrderNum())
            .deptCode(dept.getDeptCode())
            .deptType(dept.getDeptType())
            .deptTypeName(getDeptTypeName(dept.getDeptType()))
            .leaderId(dept.getLeaderId())
            .leaderName(dept.getLeaderName())
            .phone(dept.getPhone())
            .email(dept.getEmail())
            .address(dept.getAddress())
            .description(dept.getDescription())
            .status(dept.getStatus())
            .statusName(dept.getStatus() == 1 ? "启用" : "禁用")
            .userCount(userCount)
            .level(calculateDeptLevel(deptId))
            .deptPath(deptPath)
            .creatorId(dept.getCreatorId())
            .createTime(dept.getCreateTime())
            .updaterId(dept.getUpdaterId())
            .updateTime(dept.getUpdateTime())
            .build();
    }

    @Override
    public List<DeptTreeNodeVO> getDeptTree() {
        // 1. 查询所有部门
        List<SysDept> allDepts = deptMapper.selectDeptTree();

        // 2. 统计每个部门的用户数量
        Map<Long, Integer> userCountMap = allDepts.stream()
            .collect(Collectors.toMap(
                SysDept::getId,
                dept -> deptMapper.countUsersByDeptId(dept.getId())
            ));

        // 3. 构建树形结构
        return buildDeptTree(allDepts, userCountMap);
    }

    @Override
    public List<SysDept> getDeptList(SysDept dept) {
        return deptMapper.selectByCondition(dept);
    }

    @Override
    public PageResult<SysDept> getDeptPage(SysDept dept, Integer pageNum, Integer pageSize) {
        PageHelper.startPage(pageNum, pageSize);
        List<SysDept> list = deptMapper.selectByCondition(dept);
        return PageResult.restPage(list);
    }

    @Override
    @Transactional
    public void updateDeptStatus(Long deptId, Integer status) {
        // 1. 检查部门是否存在
        SysDept dept = deptMapper.selectById(deptId);
        if (dept == null) {
            throw new BusinessException(ResultCode.CONFLICT,"部门不存在");
        }

        // 2. 更新状态
        deptMapper.updateStatus(deptId, status, UserContext.getUserId());

        log.info("部门状态更新成功，部门ID: {}, 状态: {}", deptId, status);
    }

    @Override
    @Transactional
    public void updateDeptOrder(Long deptId, Integer orderNum) {
        // 1. 检查部门是否存在
        SysDept dept = deptMapper.selectById(deptId);
        if (dept == null) {
            throw new BusinessException(ResultCode.CONFLICT,"部门不存在");
        }

        // 2. 更新排序
        deptMapper.updateOrderNum(deptId, orderNum, UserContext.getUserId());

        log.info("部门排序更新成功，部门ID: {}, 排序: {}", deptId, orderNum);
    }

    @Override
    @Transactional
    public void batchUpdateDeptOrder(List<SysDept> deptOrders) {
        if (deptOrders == null || deptOrders.isEmpty()) {
            return;
        }

        // 设置更新人ID
        deptOrders.forEach(dept -> dept.setUpdaterId(UserContext.getUserId()));

        // 批量更新
        deptMapper.batchUpdateOrderNum(deptOrders);

        log.info("批量更新部门排序成功，更新数量: {}", deptOrders.size());
    }

    @Override
    public boolean existsByName(String name, Long parentId, Long excludeId) {
        return deptMapper.existsByName(name, parentId, excludeId);
    }

    @Override
    public boolean existsByDeptCode(String deptCode, Long excludeId) {
        return deptMapper.existsByDeptCode(deptCode, excludeId);
    }

    @Override
    public List<Long> getChildDeptIds(Long deptId) {
        return deptMapper.selectChildDeptIds(deptId);
    }

    @Override
    public String getDeptPath(Long deptId) {
        return deptMapper.selectDeptPath(deptId);
    }

    @Override
    public int countUsersByDeptId(Long deptId) {
        return deptMapper.countUsersByDeptId(deptId);
    }

    @Override
    @Transactional
    public void moveDept(Long deptId, Long newParentId) {
        // 1. 检查部门是否存在
        SysDept dept = deptMapper.selectById(deptId);
        if (dept == null) {
            throw new BusinessException(ResultCode.CONFLICT,"部门不存在");
        }

        // 2. 检查新父部门是否存在
        if (newParentId != null && newParentId != 0) {
            SysDept parentDept = deptMapper.selectById(newParentId);
            if (parentDept == null) {
                throw new BusinessException(ResultCode.CONFLICT,"父部门不存在");
            }
        }

        // 3. 检查是否移动到自己的子部门
        List<Long> childIds = deptMapper.selectChildDeptIds(deptId);
        if (childIds.contains(newParentId)) {
            throw new BusinessException(ResultCode.CONFLICT,"不能将部门移动到自己的子部门下");
        }

        // 4. 更新父部门ID
        deptMapper.updateChildrenParentId(deptId, newParentId, UserContext.getUserId());

        log.info("部门移动成功，部门ID: {}, 新父部门ID: {}", deptId, newParentId);
    }

    // ================== 私有方法 ==================

    /**
     * 验证创建部门参数
     */
    private void validateCreateDept(CreateDeptDTO dto) {
        if (dto == null) {
            throw new BusinessException(ResultCode.CONFLICT,"创建部门参数不能为空");
        }
        if (!StringUtils.hasText(dto.getName())) {
            throw new BusinessException(ResultCode.CONFLICT,"部门名称不能为空");
        }
        if (dto.getParentId() == null) {
            throw new BusinessException(ResultCode.CONFLICT,"父部门ID不能为空");
        }
    }

    /**
     * 验证更新部门参数
     */
    private void validateUpdateDept(UpdateDeptDTO dto) {
        if (dto == null) {
            throw new BusinessException(ResultCode.CONFLICT,"更新部门参数不能为空");
        }
        if (dto.getDeptId() == null) {
            throw new BusinessException(ResultCode.CONFLICT,"部门ID不能为空");
        }
    }

    /**
     * 获取部门类型名称
     */
    private String getDeptTypeName(Integer deptType) {
        if (deptType == null) return "";
        switch (deptType) {
            case 1: return "公司";
            case 2: return "部门";
            case 3: return "小组";
            default: return "未知";
        }
    }

    /**
     * 计算部门层级
     */
    private Integer calculateDeptLevel(Long deptId) {
        String path = deptMapper.selectDeptPath(deptId);
        if (path == null) return 1;
        return path.split("/").length;
    }

    /**
     * 构建部门树形结构
     */
    private List<DeptTreeNodeVO> buildDeptTree(List<SysDept> allDepts, Map<Long, Integer> userCountMap) {
        // 构建ID到部门的映射
        Map<Long, SysDept> deptMap = allDepts.stream()
            .collect(Collectors.toMap(SysDept::getId, dept -> dept));

        // 构建父子关系映射
        Map<Long, List<SysDept>> parentChildMap = allDepts.stream()
            .collect(Collectors.groupingBy(SysDept::getParentId));

        // 递归构建树形结构
        return buildDeptTreeRecursive(0L, deptMap, parentChildMap, userCountMap);
    }

    /**
     * 递归构建部门树形结构
     */
    private List<DeptTreeNodeVO> buildDeptTreeRecursive(Long parentId, Map<Long, SysDept> deptMap,
                                                        Map<Long, List<SysDept>> parentChildMap,
                                                        Map<Long, Integer> userCountMap) {
        List<SysDept> children = parentChildMap.get(parentId);
        if (children == null) {
            return new ArrayList<>();
        }

        return children.stream()
            .map(dept -> {
                List<DeptTreeNodeVO> childNodes = buildDeptTreeRecursive(dept.getId(), deptMap, parentChildMap, userCountMap);
                
                return DeptTreeNodeVO.builder()
                    .id(dept.getId())
                    .name(dept.getName())
                    .parentId(dept.getParentId())
                    .orderNum(dept.getOrderNum())
                    .deptCode(dept.getDeptCode())
                    .deptType(dept.getDeptType())
                    .deptTypeName(getDeptTypeName(dept.getDeptType()))
                    .leaderId(dept.getLeaderId())
                    .leaderName(dept.getLeaderName())
                    .status(dept.getStatus())
                    .statusName(dept.getStatus() == 1 ? "启用" : "禁用")
                    .userCount(userCountMap.getOrDefault(dept.getId(), 0))
                    .level(calculateDeptLevel(dept.getId()))
                    .deptPath(deptMapper.selectDeptPath(dept.getId()))
                    .isLeaf(childNodes.isEmpty())
                    .children(childNodes)
                    .build();
            })
            .collect(Collectors.toList());
    }
}
